package com.yqw.onlineDocs.aop;

import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yqw.onlineDocs.annotation.DocumentPermissionCheck;
import com.yqw.onlineDocs.common.ErrorCode;
import com.yqw.onlineDocs.constant.DocumentPermissionConstant;
import com.yqw.onlineDocs.exception.BusinessException;
import com.yqw.onlineDocs.model.entity.Document;
import com.yqw.onlineDocs.model.entity.DocumentUser;
import com.yqw.onlineDocs.model.entity.User;
import com.yqw.onlineDocs.model.enums.DocumentPermissionEnum;
import com.yqw.onlineDocs.model.enums.UserRoleEnum;
import com.yqw.onlineDocs.service.DocumentService;
import com.yqw.onlineDocs.service.DocumentUserService;
import com.yqw.onlineDocs.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;

/**
 * 文档权限校验 AOP
 */
@Aspect
@Component
@Slf4j
public class DocumentPermissionInterceptor {

  @Resource
  private UserService userService;

  @Resource
  private DocumentService documentService;

  @Resource
  private DocumentUserService documentUserService;

  /**
   * 执行拦截
   *
   * @param joinPoint
   * @param documentPermissionCheck
   * @return
   */
  @Around("@annotation(documentPermissionCheck)")
  public Object doInterceptor(ProceedingJoinPoint joinPoint, DocumentPermissionCheck documentPermissionCheck)
      throws Throwable {
    // 获取注解中的权限要求
    String requiredPermission = documentPermissionCheck.permission();
    String documentIdParam = documentPermissionCheck.documentIdParam();
    boolean fromRequestBody = documentPermissionCheck.fromRequestBody();

    // 获取请求和当前登录用户
    RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
    HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
    User loginUser = userService.getLoginUser(request);

    // 系统管理员直接放行
    if (UserRoleEnum.ADMIN.getValue().equals(loginUser.getUserRole())) {
      return joinPoint.proceed();
    }

    // 获取方法名，用于判断是否为列表查询方法
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    String methodName = signature.getMethod().getName();
    boolean isList = methodName.contains("list") || methodName.contains("List") || methodName.contains("page")
        || methodName.contains("Page");

    // 获取文档ID
    Long documentId = getDocumentId(joinPoint, documentIdParam, fromRequestBody);
    if (documentId == null || documentId <= 0) {
      // 如果是列表查询方法，则允许继续执行
      if (isList) {
        log.info("列表查询方法 {} 无需文档ID权限校验，直接放行", methodName);
        return joinPoint.proceed();
      }
      throw new BusinessException(ErrorCode.PARAMS_ERROR, "文档ID不合法");
    }

    // 检查文档是否存在
    Document document = documentService.getById(documentId);
    if (document == null) {
      throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "文档不存在");
    }

    // 文档创建者直接放行
    if (document.getUserId().equals(loginUser.getId())) {
      return joinPoint.proceed();
    }

    // 查询用户在该文档中的权限
    QueryWrapper<DocumentUser> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("documentId", documentId);
    queryWrapper.eq("userId", loginUser.getId());
    DocumentUser documentUser = documentUserService.getOne(queryWrapper);

    // 用户不在文档成员列表中
    if (documentUser == null) {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "您没有权限访问该文档");
    }

    // 检查用户权限是否满足要求
    String userPermission = documentUser.getPermission();
    DocumentPermissionEnum userPermissionEnum = DocumentPermissionEnum.getEnumByValue(userPermission);
    if (userPermissionEnum == null) {
      throw new BusinessException(ErrorCode.SYSTEM_ERROR, "权限配置错误");
    }

    // 根据权限枚举和权限配置检查用户是否有权限
    boolean hasPermission = checkPermission(userPermissionEnum, requiredPermission);
    if (!hasPermission) {
      throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "您没有权限执行此操作");
    }

    // 通过权限校验，放行
    return joinPoint.proceed();
  }

  /**
   * 从请求中获取文档ID
   *
   * @param joinPoint
   * @param documentIdParam
   * @param fromRequestBody
   * @return
   */
  private Long getDocumentId(ProceedingJoinPoint joinPoint, String documentIdParam, boolean fromRequestBody) {
    Object[] args = joinPoint.getArgs();//args：包含实际传递的参数值。
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();
    Method method = signature.getMethod();
    Parameter[] parameters = method.getParameters();//parameters：包含参数的定义信息（如参数名、类型等）

    // 从请求体中获取文档ID
    if (fromRequestBody) {
      for (int i = 0; i < parameters.length; i++) {
        Object arg = args[i];
        if (arg == null) {
          continue;
        }
        // 尝试从请求对象中获取documentId字段
        try {
          // 如果是基本类型，跳过
          if (arg instanceof HttpServletRequest) {
            continue;
          }
          // 反射获取documentId字段
          java.lang.reflect.Field field = arg.getClass().getDeclaredField(documentIdParam);
          field.setAccessible(true);
          Object value = field.get(arg);
          System.out.println(value);
          if (value instanceof Long) {
            return (Long) value;
          } else if (value instanceof Integer) {
            return ((Integer) value).longValue();
          } else if (value instanceof String) {
            return Long.parseLong((String) value);
          }
        } catch (Exception e) {
          // 该对象没有documentId字段，继续检查下一个参数
          log.debug("Failed to get documentId from request body", e);
        }
      }
    }
    // 从URL参数中获取文档ID
    else {
      RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
      HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
      String documentIdStr = request.getParameter(documentIdParam);
      if (ObjUtil.isNotEmpty(documentIdStr)) {
        try {
          return Long.parseLong(documentIdStr);
        } catch (NumberFormatException e) {
          log.error("Invalid documentId format: {}", documentIdStr);
        }
      }
    }
    return null;
  }

  /**
   * 检查用户权限是否满足要求
   *
   * @param userPermissionEnum 用户权限枚举
   * @param requiredPermission 需要的权限
   * @return 是否有权限
   */
  private boolean checkPermission(DocumentPermissionEnum userPermissionEnum, String requiredPermission) {
    // 如果没有指定需要的权限，默认放行
    if (ObjUtil.isEmpty(requiredPermission)) {
      return true;
    }
    // 根据用户角色获取对应的权限列表
    List<String> userPermissions;
    switch (userPermissionEnum) {
      case ADMIN:
        userPermissions = Arrays.asList(
            DocumentPermissionConstant.DOCUMENT_USER_MANAGE,
            DocumentPermissionConstant.DOCUMENT_READ,
            DocumentPermissionConstant.DOCUMENT_WRITE);
        break;
      case EDITOR:
        userPermissions = Arrays.asList(
            DocumentPermissionConstant.DOCUMENT_READ,
            DocumentPermissionConstant.DOCUMENT_WRITE);
        break;
      case VIEWER:
        userPermissions = Arrays.asList(
            DocumentPermissionConstant.DOCUMENT_READ);
        break;
      default:
        return false;
    }
    // 检查用户是否拥有所需权限
    return userPermissions.contains(requiredPermission);
  }
}